using System;
using System.Collections.Generic;
using System.Text;
using Mpi.Common.Collections;
using System.ComponentModel;
using Xeml.Document.Contracts;
using System.Diagnostics;

namespace Xeml.Document
{
    /// <summary>
    /// Represents the parameter of the xeml terminology.
    /// </summary>
    public class Variable2 : XemlAnnotatableObject, INotifyPropertyChanged, ISupervisableTerm
    {
        #region Fields
        private string _name;
        private string _nameSpaceAlias;
        private string _groupPath;
        private DynamicValueCollection _values;
        private string _nameSpace;

      

        #endregion

        #region Properties
        /// <summary>
        /// The name of the Parameter.
        /// </summary>
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {

                string oldVal = this.FqName;
                string newVal = BuildFqName(_nameSpaceAlias,_groupPath , value);



                if (oldVal != newVal)
                {
                    if (this.collection != null && this.collection.Contains(newVal))
                        throw new ArgumentException(String.Format("The parameter '{0}' already exist!", newVal));
                    this._name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        /// <summary>
        /// The path to the group where this parameter is located
        /// </summary>
        public string GroupPath
        {
            get
            {
                return this._groupPath;
            }
            set
            {
              

                string oldVal = this.FqName;
                string newVal = BuildFqName(_nameSpaceAlias, value, _name);



                if (oldVal != newVal)
                {
                    if (this.collection != null && this.collection.Contains(newVal))
                        throw new ArgumentException(String.Format("The parameter '{0}' already exist!", newVal));
                    this._groupPath = value;
                    OnPropertyChanged("GroupPath");
                }
            }
        }

        /// <summary>
        /// The group where this parameter is located.
        /// </summary>
        public string Group
        {
            get
            {
                string[] t = this._groupPath.Split('.');
                return t[t.Length - 1];
            }
        }


      
        public string NameSpaceAlias
        {
            get
            {
                //if (String.IsNullOrEmpty(this._nameSpaceAlias))
                //    return "none";
                //else
                    return this._nameSpaceAlias;
            }
            set
            {

                string oldVal = this.FqName;
                string newVal = BuildFqName(value, _groupPath , _name);

                if (oldVal != newVal)
                {
                    if (this.collection != null && this.collection.Contains(newVal))
                        throw new ArgumentException(String.Format("The parameter '{0}' already exist!", newVal));
                    this._nameSpaceAlias = value;
                    OnPropertyChanged("NameSpaceAlias");
                }

            }
        }


        /// <summary>
        /// The namespace where this parameter is contained.
        /// </summary>
        /// <remarks>The get method return "none" by default if the namespace attribute is not specified.</remarks>
        public string NameSpace
        {
            get { return _nameSpace; }
            set
            {
                //string oldVal = this.FqName;
                //string newVal = BuildFqName(value, this._groupPath, this._name);

                //if (oldVal != newVal)
                //{
                //    if (this.collection != null && this.collection.Contains(newVal))
                //        throw new ArgumentException(String.Format("The parameter '{0}' already exist!", newVal));
                    this._nameSpace = value;
                    OnPropertyChanged("NameSpace");
               // }
            }
        }

        /// <summary>
        /// The full qualified name. Is a combination of the name space followed by the name and separated by a colon.
        /// </summary>
        /// <exception cref="System.FormatException">Will be throwed if the passed value has a wrong format. Correct formats are like 'MyNameSpace:MyParameter'.</exception>
        public string FqName
        {
            get
            {
                return BuildFqName(_nameSpaceAlias, _groupPath, _name);
               
            }
            set
            {
                string[] temp = value.Split(':');
                if (temp.Length != 2)
                {
                    throw new FormatException("The value has the wrong format.");
                }
                else
                {
                    string oldVal = this.FqName;
                  
                    this._nameSpace = temp[0];

                    string[] temp2 = temp[1].Split('.');
                    if (temp2.Length <= 1)
                        this._name = temp2[0];
                    else
                    {
                        this._name = temp2[temp2.Length-1];
                        StringBuilder groupBuilder = new StringBuilder();
                        for (int i = 0; i < temp2.Length-2; i++)
                        {
                            groupBuilder.AppendFormat("{0}.", temp2[i]);
                        }
                        groupBuilder.Remove(groupBuilder.Length - 1, 1);
                        this._groupPath = groupBuilder.ToString();
                    }
                  
                    if (oldVal != this.FqName)
                    {
                        OnPropertyChanged("FqName");
                    }
                }
            }
        }

        private string BuildFqName(string nameSpaceAlias, string groupPath, string name)
        {

            string withGroup = "";
            if (String.IsNullOrEmpty(groupPath))
            {
                withGroup = name;
            }
            else
            {
                withGroup = String.Format("{0}.{1}", groupPath, name);
            }


            if (String.IsNullOrEmpty(nameSpaceAlias) || "none".Equals(nameSpaceAlias.ToLower()))
            {
                return withGroup;
            }
            else
            {
                return String.Format("{0}:{1}", nameSpaceAlias, withGroup);
            }
        }


        /// <summary>
        /// The value collection of the default property.
        /// </summary>
        
        ///<seealso cref="Xeml."/>
        public DynamicValueCollection Values
        {
            get
            {
                return this._values;
            }
        }

        /// <summary>
        
        #endregion

        #region Constructors


        /// <summary>
        /// The default constructor.
        /// </summary>
        public Variable2()
        {
          
            this._values = new DynamicValueCollection();
            this._values.CollectionChanged += new EventHandler(OnValueCollectionChanged);
        }

        /// <summary>
        /// A parameterized contructor.
        /// </summary>
        public Variable2(string termId) : this()
        {
            _termId = termId;
          
        }

       
        /// <summary>
        /// A parameterized contructor.
        /// </summary>
        /// <param name="nameSpace"></param>
        /// <param name="groupPath"></param>
        /// <param name="name"></param>
        public Variable2(string termId,string nameSpace, string groupPath, string name) :this(termId)
        {
            this._nameSpaceAlias = nameSpace;
            this._groupPath = groupPath;
            this._name = name;
        }

        #endregion

        #region Methods


        /// <summary>
        /// An eventhandler for changed values.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnValueCollectionChanged(object sender, EventArgs e)
        {
            Debug.WriteLine("Parameter: Values cahnged");
            OnPropertyChanged("Values");
        }


        /// <summary>
        /// Generates a string representation of this object.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.FqName;
        }

        /// <summary>
        /// Lists all contexts.
        /// </summary>
        /// <returns></returns>
        public List<string> ContextList()
        {
            List<string> ret = new List<string>();
            foreach (ValueBase vb in this._values)
            {
                if (!ret.Contains(vb.Context))
                    ret.Add(vb.Context);
            }
            return ret;
        }

        /// <summary>
        /// Returns all values of an given context.
        /// </summary>
        /// <param name="context">The context to filter.</param>
        /// <returns>A list of values.</returns>
        public List<DynamicValueBase> ValueBy(string context)
        {
            return this._values.FindAll(delegate(DynamicValueBase vb) { return vb.Context == context; });
        }

        #endregion


        private VariableCollection collection;
        public VariableCollection Collection
        {
            get
            {
                return this.collection;
            }
            set
            {
                if (value != collection)
                {
                    this.collection = value;
                }

            }
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        #endregion
    
        #region ISupervisableTerm Members

        private string _termId;
        public string TermId
        {
            get { return _termId; }
        }

        #endregion
    }
}
